﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Globalization;
using debugger;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;

namespace debugger
{

    public sealed partial class Form1 : Base
    {
        public const byte SET_DEBUG_RW_CMD = 0x15;//{debug_mem_dummy,debug_rw_cmd} <= data[3:0];

        public const byte MEM_TRANS_READ = 0x34;
        public const byte MEM_TRANS_WRITE = 0x35;
        //public const byte REG_READ = 0x37;
        public const byte TRANS_READ = 0x38;
        public const byte TRANS_WRITE = 0x39;






        public static uint CACHE_CTL = 0x42000000;

        public const byte HALT_DEBUG = 0x10;
        public const byte SET_CPU_CLK = 0x11;
        public const byte DEBUG_RESET_N = 0x12;

        public const byte DEBUG_STEP = 0x14;
        
        public const byte SET_DEBUG_ADDRESS = 0x16;
        public const byte SET_DEBUG_WRITEDATA = 0x17;
        public const byte SET_DEBUG_VGA_BASE_ADDR = 0x18;
        public const byte SET_DEBUG_FLG = 0x19;
        public const byte SET_DEBUG_HID = 0x1A;
        public const byte SET_DEBUG_HID_REQ = 0x1B;
        public const byte SET_DEBUG_LENGTH = 0x1C;
        public const byte SET_DEBUG_ECHO = 0x1F;

        //public const byte GET_ECHO = 0x1C;
        public const byte GET_CONST_ECHO = 0x20;
        public const byte GET_CONST_VER = 0x24;

        public const byte GET_DEBUG8 = 0x20;
        public const byte GET_DEBUG32 = 0x21;
        public const byte GET_ACCESS_TIME = 0x22;
        public const byte GET_AVM_M0_ADDRESS = 0x23;
        //public const byte GET_PRIVATE_OFFSET_REAR = 0x24;

        public const byte GET_PC_RECORD_DATA = 0x25;
        public const byte GET_PC_RECORD_DATA_EXT = 0x21;
        public const byte GET_PC_RECORD_INDEX = 0x26;
        public const byte GET_MISC = 0x27;
        //public const byte GET_IRQ_ADDR = 0x28;
        public const byte GET_IRQ_ID = 0x28;
        public const byte GET_CPU_ADDRESS = 0x29;
        public const byte GET_PC = 0x2A;
        //public const byte GET_PRIVATE_OFFSET = 0x2B;
        //public const byte GET_PC_RESULT = 0x2C;
        //public const byte GET_CURR_DATA = 0x2D;
        
        public const byte GET_MEM_SIZE = 0x2B;
        public const byte GET_VGA_BASE_ADDR = 0x2C;
        
        public const byte GET_DEBUG_STASH_DATA = 0x2E;
        public const byte GET_DEBUG_STASH_INDEX = 0x2F;

        public const byte MEM_READ = 0x30;
        public const byte MEM_WRITE = 0x31;
        public const byte INS_READ = 0x32;
        public const byte REG_READ = 0x33;
        public const byte MEM_READ_TRANS = 0x34;
        public const byte MEM_WRITE_TRANS = 0x35;
        public const byte INS_READ_TRANS = 0x36;
        public const byte VGA_TRANS = 0x37;

        //public const byte MEM_TRANS_READ = 0x34;
        //public const byte MEM_TRANS_WRITE = 0x35;
        //public const byte TRANS_READ = 0x38;
        //public const byte TRANS_WRITE = 0x39;


        //public const byte DEBUG_TX_TO_PC = 0x40;
        //public const byte DEBUG_TX_STATUS_TO_PC = 0x41;
        //public const byte DEBUG_RX_FROM_PC = 0x42;
  



        public const byte SPIROM_DEBUG_CS0 = 0x70;
        public const byte SPIROM_DEBUG_CS1 = 0x71;
        public const byte SPIROM_REC = 0x72;
        public const byte SPIROM_SND = 0x73;
        public const byte SPIROM_SND4 = 0x74;
        public const byte SPIROM_TRANS_WRITE = 0x76;


        public Form1()
        {
            InitializeComponent();

            this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);


        }

        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
        }
        string portName;

        System.Threading.Timer t;

        void timer(Object a)
        {
            uint data = sendCmdRet(0x0E);
            Console.WriteLine(data);

        }
        public void afterConnect()
        {
            
            try
            {

                var echo = sendCmdRet(GET_CONST_ECHO, 0x12345678);
                if (echo == 0x12345678)
                {
                    var ver = sendCmdRet(GET_CONST_VER);
                    this.Text = "connected echo ok，" + Util.getHex8(ver);
                    Console.WriteLine("connected echo ok，" + Util.getHex8(ver));

                }
                else
                {
                    this.Text = "echo error：" + Util.getHex8(echo);
                    Console.WriteLine("echo error：" + Util.getHex8(echo));
                }




                ///////////////////////////////////////////////////////////////
            }
            catch (Exception ex)
            {
                this.Text = "echo ex";
            }

            uint memSize = sendCmdRet(GET_MEM_SIZE);//getmem(0x42000000, null);
            //uint pos = memSize / 1024;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                bool ret = connect(this.afterConnect);
                if (!ret)
                {
                    foreach (var item in this.Controls)
                    {
                        (item as Control).Enabled = false;
                    }
                }
            }
            catch (Exception ex) { 
            }
        }




        public uint getAccessTime()
        {
            if (!isBasic)
            {
                return sendCmdRet(GET_ACCESS_TIME);
            }
            else
            {
                return 0;
            }
        }

        byte[] buff;

        private void button2_Click_1(object sender, EventArgs e)
        {
            int testSize = 64 * 1024;
            // write mem
            int size = testSize;
            buff = new byte[size];
            Random r = new Random();
            r.NextBytes(buff);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            writeUSB3(buff, size);
            sw.Stop();

            double speed = (testSize / 1024.0 / 1024.0) / (sw.ElapsedMilliseconds / 1000.0);
            Console.WriteLine("done, " + speed + "M/s");
        }

        private void button6_Click(object sender, EventArgs e)
        {
            int testSize = 64 * 1024;
            int size = testSize;
            byte[] buff2 = new byte[size];
            Stopwatch sw = new Stopwatch();
            sw.Start();
            readUSB3(buff2, size);
            int err = 0;
            int errCnt = 0;
            for (int i = 0; i < size; i += 4)
            {
                uint v1 = 0;
                if (buff != null)
                {
                    v1 |= (((uint)buff[i + 0]) & 0xFF);
                    v1 |= (((uint)buff[i + 1]) & 0xFF) << 8;
                    v1 |= (((uint)buff[i + 2]) & 0xFF) << 16;
                    v1 |= (((uint)buff[i + 3]) & 0xFF) << 24;
                }
                uint v2 = 0;
                {
                    v2 |= (((uint)buff2[i + 0]) & 0xFF);
                    v2 |= (((uint)buff2[i + 1]) & 0xFF) << 8;
                    v2 |= (((uint)buff2[i + 2]) & 0xFF) << 16;
                    v2 |= (((uint)buff2[i + 3]) & 0xFF) << 24;
                }
                if (v1 != v2)
                {
                    err++;
                    errCnt++;
                    if (errCnt > 32)
                    {

                    }
                    else
                    {
                        Console.WriteLine(i + "," + Util.getHex8(v1) + "," + Util.getHex8(v2) + ", " + (v1 != v2 ? "x" : " "));
                    }
                }
                //if (i == 0 || i == 4 || i == 8 || i == 12)
                //{
                //    Console.WriteLine(i + "*," + Util.getHex8(v1) + "," + Util.getHex8(v2));
                //}
            }

            double speed = (testSize / 1024.0 / 1024.0) / (sw.ElapsedMilliseconds / 1000.0);

            Console.WriteLine("err:" + err + ", " + speed + "M/s");

        }

        //const int TRANS_COUNT = 4;
        const int TRANS_COUNT = 32;//128byte
        //const int TRANS_COUNT = 64;//2048byte
        void writeMem(byte[] buff, int size, int addr)
        {
            sendCmd(0x10, (uint)(size / (4 * (4 * TRANS_COUNT)) - 1));//ddr2_trans_end
            sendCmd(Form1.SET_DEBUG_ADDRESS, (uint)(addr / 8));//debug_address

            int xferLen = size;

            sendCmd(0x02, 1);//reset_fifo
            sendCmd(0x02, 0);//reset_fifo

            sendCmd(0x01, 0);//ft_out_to_pc

            sendCmd(0x04, 1);//transfer_req
            bool bResult = pc2fpgaTrans(ref buff, ref xferLen);
            //Thread.Sleep(10);
            while (true)
            {
                uint mem_status = sendCmdRet(0x2A);
                if (mem_status == 7)
                {
                    break;
                }
            }

            sendCmd(0x04, 0);//transfer_req
        }

        void readMem(byte[] buff, int size, int addr)
        {
            //read mem
            sendCmd(0x10, (uint)(size / (4 * (4 * TRANS_COUNT)) - 1));//ddr2_trans_end
            sendCmd(Form1.SET_DEBUG_ADDRESS, (uint)(addr / 8));//debug_address

            int xferLen = size;

            sendCmd(0x02, 1);//reset_fifo
            sendCmd(0x02, 0);//reset_fifo

            sendCmd(0x01, 1);//ft_out_to_pc

            sendCmd(0x04, 1);//transfer_req
            bool bResult = fpga2pcTrans(ref buff, ref xferLen);
            //Thread.Sleep(100);
            while (true)
            {
                uint mem_status = sendCmdRet(0x2A);
                if (mem_status == 7)
                {
                    break;
                }
            }

            sendCmd(0x04, 0);//transfer_req
        }


        private void button5_Click(object sender, EventArgs e)
        {
            this.connect(this.afterConnect);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            int testSize = 16 * 1024 * 1024;
            // write mem
            int size = testSize;
            buff = new byte[size];
            Random r = new Random();
            r.NextBytes(buff);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            writeMem(buff, size, size);
            sw.Stop();

            double speed = (testSize / 1024.0 / 1024.0) / (sw.ElapsedMilliseconds / 1000.0);
            Console.WriteLine("done, " + speed + "M/s");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int testSize = 16 * 1024 * 1024;
            int size = testSize;
            byte[] buff2 = new byte[size];
            Stopwatch sw = new Stopwatch();
            sw.Start();
            readMem(buff2, size, size);
            int err = 0;
            int errCnt = 0;
            for (int i = 0; i < size; i += 4)
            {
                uint v1 = 0;
                if (buff != null)
                {
                    v1 |= (((uint)buff[i + 0]) & 0xFF);
                    v1 |= (((uint)buff[i + 1]) & 0xFF) << 8;
                    v1 |= (((uint)buff[i + 2]) & 0xFF) << 16;
                    v1 |= (((uint)buff[i + 3]) & 0xFF) << 24;
                }
                uint v2 = 0;
                {
                    v2 |= (((uint)buff2[i + 0]) & 0xFF);
                    v2 |= (((uint)buff2[i + 1]) & 0xFF) << 8;
                    v2 |= (((uint)buff2[i + 2]) & 0xFF) << 16;
                    v2 |= (((uint)buff2[i + 3]) & 0xFF) << 24;
                }
                if (v1 != v2)
                {
                    err++;
                    errCnt++;
                    if (errCnt > 32)
                    {

                    }
                    else
                    {
                        Console.WriteLine(i + "," + Util.getHex8(v1) + "," + Util.getHex8(v2) + ", " + (v1 != v2 ? "x" : " "));
                    }
                }
                //if (i == 0 || i == 4 || i == 8 || i == 12)
                //{
                //    Console.WriteLine(i + "*," + Util.getHex8(v1) + "," + Util.getHex8(v2));
                //}
            }

            double speed = (testSize / 1024.0 / 1024.0) / (sw.ElapsedMilliseconds / 1000.0);

            Console.WriteLine("err:" + err + ", " + speed + "M/s");

        }

        void writeUSB3(byte[] buff, int size)
        {

            int xferLen = size;

            sendCmd(0x02, 1);//reset_fifo
            sendCmd(0x02, 0);//reset_fifo

            sendCmd(0x01, 0);//ft_out_to_pc

            sendCmd(0x04, 1);//transfer_req
            bool bResult = pc2fpgaTrans(ref buff, ref xferLen);
            Thread.Sleep(300);

            sendCmd(0x04, 0);//transfer_req
        }

        void readUSB3(byte[] buff, int size)
        {

            int xferLen = size;

            sendCmd(0x02, 1);//reset_fifo
            sendCmd(0x02, 0);//reset_fifo

            sendCmd(0x01, 1);//ft_out_to_pc

            sendCmd(0x04, 1);//transfer_req
            bool bResult = fpga2pcTrans(ref buff, ref xferLen);
            Thread.Sleep(300);
           
            sendCmd(0x04, 0);//transfer_req
        }

    }
}
